<?php
/**
 * @Author: gan
 * @Description:
 * @File:  YiLianYunImpl
 * @Version: 1.0.0
 * @Date: 2022/5/24 9:25 上午
 */
declare(strict_types=1);

namespace RX\Component\CloudPrint\Impl;

use Psr\SimpleCache\CacheInterface;
use RX\Enums\CommonEnum;
use RX\Enums\NetworkEnum;
use RX\Exception\BizException;
use RX\Helpers\RandomHelper;
use RX\Traits\CurlTrait;

class YiLianYunImpl
{
    use CurlTrait;

    protected string $host = 'https://open-api.10ss.net/';

    protected array $config;

    protected CacheInterface $cache;


    public function __construct(array $config, CacheInterface $cache)
    {
        if (!isset($config['client_id']) || !isset($config['client_secret'])) {
            throw new BizException(CommonEnum::class, CommonEnum::INVALID_PARAMS, "请检查client_id与client_secret是否配置");
        }
        $this->config = $config;
        $this->cache  = $cache;
    }


    public function register(array $params)
    {
        return $this->request('printer/addprinter', $params);
    }

    public function delete(array $params)
    {
        return $this->request('printer/deleteprinter', $params);
    }

    public function status(array $params)
    {
        return $this->request('printer/getprintstatus', $params);
    }

    public function restart(array $params)
    {
        return $this->request('printer/shutdownrestart', $params);
    }

    public function setSound(array $params)
    {
        return $this->request('printer/setsound', $params);
    }


    public function setVoice(array $params)
    {
        return $this->request('printer/setvoice', $params);
    }


    public function deleteVoice(array $params)
    {
        return $this->request('printer/deletevoice', $params);
    }

    public function print(array $params, string $type = "")
    {
        if ($type == 'pic') {
            return $this->picPrint($params);
        }
        if ($type == 'express') {
            return $this->expressPrint($params);
        }

        return $this->textPrint($params);
    }

    public function textPrint(array $params)
    {
        return $this->request('print/index', $params);
    }


    public function picPrint(array $params)
    {
        return $this->request('pictureprint/index', $params);
    }


    public function expressPrint(array $params)
    {
        return $this->request('expressprint/index', $params);
    }


    public function clean(array $params)
    {
        return $this->request('printer/cancelone', $params);
    }

    public function cleanAll(array $params)
    {
        return $this->request('printer/cancelall', $params);
    }


    public function orderState(array $params)
    {
        return $this->request('printer/getorderstatus', $params);
    }

    public function orderList(array $params)
    {
        return $this->request('printer/getorderpaginglist', $params);
    }


    public function request(string $action, array $params)
    {
        $timestamp    = time();
        $publicParams = [
            'client_id' => $this->config['client_id'],
            'sign'      => $this->sign($timestamp),
            'timestamp' => $timestamp,
            'id'        => RandomHelper::makeUUIDV4(),
        ];
        if ($action != 'oauth/oauth') {
            $publicParams['access_token'] = $this->accessToken();
        }
        $url    = $this->buildHost($action);
        $params = array_filter(array_merge($publicParams, $params));
        $body   = self::postCurl($url, $params, false, 5, ['Content-Type: application/x-www-form-urlencoded']);
        return self::checkResponse($body);
    }

    protected function accessToken()
    {
        $key        = $this->config['client_id'];
        $cacheToken = $this->cache->get($key);
        if ($cacheToken) {
            return $cacheToken;
        }
        $params = [
            'grant_type' => 'client_credentials',
            'scope'      => 'all',
        ];
        $resp   = $this->request('oauth/oauth', $params);
        $this->cache->set($key, $resp['body']['access_token'], $resp['body']['expires_in']);
        return $resp['body']['access_token'];
    }

    protected function buildHost(string $action)
    {
        return $this->config['host'] ?? $this->host . $action;
    }

    protected function sign(int $timestamp)
    {
        return md5($this->config['client_id'] . $timestamp . $this->config['client_secret']);
    }

    protected function checkResponse($body): array
    {
        $body = json_decode($body, true);
        if (empty($body) || !is_array($body)) {
            throw new BizException(NetworkEnum::class, NetworkEnum::NETWORK_ERROR);
        }
        if ($body["error"] !== "0") {
            throw new BizException(CommonEnum::class, CommonEnum::INVALID_PARAMS, $body["error_description"] . "({$body["error"]})");
        }
        return $body;
    }
}
